#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow), dataPointNumber(0), channels(0)
{
    ui->setupUi(this);

    QColor gui_colors[4];

    if(1)  // 白色主题
    {
        gui_colors[0] = QColor (255,  255,  255,  255); /**<  0: qdark ui dark/background color */
        gui_colors[1] = QColor (175,  175,  175,  255); /**<  0: qdark ui dark/background color */
        gui_colors[2] = QColor (85,   85,   85,   255); /**<  0: qdark ui dark/background color */
        gui_colors[3] = QColor (207,  208,  208,  200); /**<  0: qdark ui dark/background color */

    }else
    {
        gui_colors[0] = QColor (48,  47,  47,  255); /**<  0: qdark ui dark/background color */
        gui_colors[1] = QColor (80,  80,  80,  255); /**<  1: qdark ui medium/grid color */
        gui_colors[2] = QColor (170, 170, 170, 255); /**<  2: qdark ui light/text color */
        gui_colors[3] = QColor (48,  47,  47,  200); /**<  3: qdark ui dark/background color w/transparency */
    }

    QFont font;
    //    font.setPointSize(10);
    font.setStyleStrategy (QFont::PreferAntialias);

    // 设置背景颜色
    //    ui->plot->setBackground (gui_colors[0]);

    // 强制设置所有元素抗锯齿
    ui->plot->setNotAntialiasedElements (QCP::aeAll);

    //////////////////////////////////////////////////////////////////////
    ///
    /// 设置X轴样式
    ///

    //    ui->plot->xAxis->grid()->setPen (QPen(gui_colors[2], 1, Qt::DotLine));
    //    ui->plot->xAxis->grid()->setSubGridPen (QPen(gui_colors[1], 1, Qt::DotLine));
    //    ui->plot->xAxis->grid()->setSubGridVisible (true);
    //    ui->plot->xAxis->setBasePen (QPen (gui_colors[2]));
    //    ui->plot->xAxis->setTickPen (QPen (gui_colors[2]));
    //    ui->plot->xAxis->setSubTickPen (QPen (gui_colors[2]));
    //    ui->plot->xAxis->setTickLabelColor (gui_colors[2]);
    ui->plot->xAxis->setUpperEnding (QCPLineEnding::esSpikeArrow);
    ui->plot->xAxis->setTickLabelFont (font);
    ui->plot->xAxis->setRange (0, 100);

    //////////////////////////////////////////////////////////////////////
    ///
    /// 设置Y轴样式
    ///
    //    ui->plot->yAxis->grid()->setPen (QPen(gui_colors[2], 1, Qt::DotLine));
    //    ui->plot->yAxis->grid()->setSubGridPen (QPen(gui_colors[1], 1, Qt::DotLine));
    //    ui->plot->yAxis->grid()->setSubGridVisible (true);
    //    ui->plot->yAxis->setBasePen (QPen (gui_colors[2]));
    //    ui->plot->yAxis->setTickPen (QPen (gui_colors[2]));
    //    ui->plot->yAxis->setSubTickPen (QPen (gui_colors[2]));
    //    ui->plot->yAxis->setTickLabelColor (gui_colors[2]);
    ui->plot->yAxis->setUpperEnding (QCPLineEnding::esSpikeArrow);
    ui->plot->yAxis->setTickLabelFont (font);
    ui->plot->yAxis->setRange (0, 100);

    // 设置自动调整Y轴的tick
    //ui->plot->yAxis->setAutoTickStep (false);

    // 设置Y轴刻度数量
    ui->plot->yAxis->ticker()->setTickCount(10);

    ///////////////////////////////////////////////////////////////////////
    ///
    /// 设置用户交互仅允许在X轴上鼠标拖动和滚轮缩放，Y轴由UI控件手动固定
    ///
    ui->plot->setInteraction (QCP::iRangeDrag, true);         // 使能鼠标拖拽
    ui->plot->setInteraction (QCP::iSelectPlottables, true);  // 允许选中通道
    ui->plot->setInteraction (QCP::iSelectLegend, true);      // 允许选中图例
    ui->plot->axisRect()->setRangeDrag (Qt::Horizontal);      // 只能水平方向拖拽
    ui->plot->axisRect()->setRangeZoom (Qt::Horizontal);      // 只能水平方向滚轮

    //////////////////////////////////////////////////////////////////////
    ///
    /// 设置图例样式
    ///
    //    ui->plot->legend->setBrush(gui_colors[3]);
    //    ui->plot->legend->setBorderPen(gui_colors[2]);
    ui->plot->legend->setVisible(true);
    ui->plot->legend->setFont(font);
    ui->plot->axisRect()->insetLayout()->setInsetAlignment (0, Qt::AlignTop|Qt::AlignRight);  // 图例位置

    // 重绘
    ui->plot->replot();

    // 鼠标滚轮事件
    connect(ui->plot, &QCustomPlot::mouseWheel, this, &MainWindow::mouseWheel);

    // 鼠标指针移动事件
    connect(ui->plot, &QCustomPlot::mouseMove, this, &MainWindow::mouseMove);

    // 通道选择
    connect (ui->plot, &QCustomPlot::selectionChangedByUser, this, &MainWindow::selectionChangedByUser);

    // 图例上双击
    connect (ui->plot, &QCustomPlot::legendDoubleClick, this, &MainWindow::legendDoubleClick);

    // Y轴变化控制
    connect(ui->spboxPoints, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &MainWindow::pointsChanged);
    connect(ui->spboxMinVal, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &MainWindow::minvalChanged);
    connect(ui->spboxMaxVal, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &MainWindow::maxvalChanged);
    connect(ui->spboxTicker, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &MainWindow::tickerChanged);

#if 0
    // 添加第一路曲线
    ui->plot->addGraph();
    ui->plot->graph(0)->setPen(QPen(QColor(255, 0, 0)));
    ui->plot->graph(0)->setName(tr("温度（℃）"));
    ui->plot->legend->item(0)->setTextColor(QColor(255, 0, 0));

    // 添加第二路曲线
    ui->plot->addGraph();
    ui->plot->graph(1)->setPen(QPen(QColor(0, 0, 255)));
    ui->plot->graph(1)->setName(tr("湿度（RH%）"));
    ui->plot->legend->item(1)->setTextColor(QColor(0, 0, 255));
#endif

    // 自适应
    connect(ui->btnAutoScale, &QPushButton::clicked, this, &MainWindow::autuScale);

    // 清除显示
    connect(ui->btnClearPlottables, &QPushButton::clicked, this, &MainWindow::clearPlottables);

    // 20ms重绘制一次
    connect(&updateTimer, &QTimer::timeout, this, &MainWindow::replot);
    updateTimer.start(20);

    // 模拟数据
    connect(&newDataTimer, &QTimer::timeout, this, &MainWindow::newData);

    // 启动和停止模拟绘图
    connect(ui->btnStartPlot, &QPushButton::clicked, this, &MainWindow::startPlot);
    connect(ui->btnStopPlot, &QPushButton::clicked, this, &MainWindow::stopPlot);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::replot()
{
    if(dataPointNumber > ui->spboxPoints->value())
    {
        ui->plot->xAxis->setRange (dataPointNumber - ui->spboxPoints->value(), dataPointNumber);
    }else
    {
        ui->plot->xAxis->setRange (0, ui->spboxPoints->value());
    }
    ui->plot->replot();
}

void MainWindow::pointsChanged(int value)
{
    int step = (float)value * 0.025f;  // 缩放因子0.025，在原来的值得基础上增加/减少0.025倍
    if(step == 0)
    {
        step = 1;
    }
    ui->spboxPoints->setSingleStep(step);
    if(dataPointNumber > value)
    {
        ui->plot->xAxis->setRange (dataPointNumber - value, dataPointNumber);
    }else
    {
        ui->plot->xAxis->setRange (0, value);
    }
    ui->plot->replot();
}

void MainWindow::minvalChanged(int value)
{
    int step = (float)abs(value) * 0.025f;  // 缩放因子0.025，在原来的值得基础上增加/减少0.025倍
    if(step == 0)
    {
        step = 1;
    }
    ui->spboxMinVal->setSingleStep(step);
    ui->plot->yAxis->setRangeLower(value);
    ui->plot->replot();
}

void MainWindow::maxvalChanged(int value)
{
    int step = (float)abs(value) * 0.025f;  // 缩放因子0.025，在原来的值得基础上增加/减少0.025倍
    if(step == 0)
    {
        step = 1;
    }
    ui->spboxMinVal->setSingleStep(step);
    ui->plot->yAxis->setRangeUpper(value);
    ui->plot->replot();
}

void MainWindow::tickerChanged(int value)
{
    ui->plot->yAxis->ticker()->setTickCount(value);
    ui->plot->replot();
}

void MainWindow::autuScale()
{
    ui->plot->yAxis->rescale(true);
    ui->spboxMaxVal->setValue(int(ui->plot->yAxis->range().upper) + int(ui->plot->yAxis->range().upper*0.1));
    ui->spboxMinVal->setValue(int(ui->plot->yAxis->range().lower) + int(ui->plot->yAxis->range().lower*0.1));
}

void MainWindow::clearPlottables()
{
    dataPointNumber = 0;
    ui->plot->clearPlottables();
    ui->plot->replot();
}

void MainWindow::startPlot()
{
    newDataTimer.start(10);
}

void MainWindow::stopPlot()
{
    newDataTimer.stop();
}

void MainWindow::mouseWheel(QWheelEvent *event)
{
    QWheelEvent inverted_event = QWheelEvent(
                event->posF(),
                event->globalPosF(),
                -event->pixelDelta(),
                -event->angleDelta(),
                0,
                Qt::Vertical,
                event->buttons(),
                event->modifiers());
    QApplication::sendEvent (ui->spboxPoints, &inverted_event);
}

void MainWindow::mouseMove(QMouseEvent *event)
{
    int xx = int(ui->plot->xAxis->pixelToCoord(event->x()));
    int yy = int(ui->plot->yAxis->pixelToCoord(event->y()));
    QString coordinates("X: %1 Y: %2");
    coordinates = coordinates.arg(xx).arg(yy);
    ui->statusbar->showMessage(coordinates);
}

void MainWindow::legendDoubleClick(QCPLegend *legend, QCPAbstractLegendItem *item, QMouseEvent *event)
{
    Q_UNUSED(legend)
    Q_UNUSED(event)
    if (item)  // 只有通道条目被点击时才会做出反应（用户可能点击了图例中但是没有点击通道条目）
    {
        bool ok;
        QCPPlottableLegendItem *legend = qobject_cast<QCPPlottableLegendItem*>(item);
        QString name = QInputDialog::getText (this, tr("设置通道名称"), tr("名称:"), QLineEdit::Normal, legend->plottable()->name(), &ok, Qt::FramelessWindowHint);
        if (ok)
        {
            legend->plottable()->setName(name);
            ui->plot->replot();
        }
    }
}

void MainWindow::selectionChangedByUser()
{
    // 将图形的选择与相应图例项的选择同步
    for (int i = 0; i < ui->plot->graphCount(); i++)
    {
        QCPGraph *graph = ui->plot->graph(i);
        QCPPlottableLegendItem *item = ui->plot->legend->itemWithPlottable (graph);
        item->setSelected(item->selected());
    }
}

void MainWindow::newData()
{
#define CHANNELS 2

    const static QColor colors[CHANNELS] = {QColor("#c0504d"), QColor("#9bbb59")};
    const static QStringList names = {QString(tr("温度（℃）")), QString(tr("湿度（RH%）"))};
    double value[CHANNELS];

    value[0] = rand() % 5 + 20;
    value[1] = rand() % 5 + 50;

    for(int i = 0; i < CHANNELS; i++)
    {
        if(ui->plot->plottableCount() <= i)
        {
            ui->plot->addGraph();
            ui->plot->graph()->setPen(QPen(colors[i % CHANNELS], 2));
            ui->plot->graph()->setName(names[i % CHANNELS]);
            if(ui->plot->legend->item(i))
            {
                ui->plot->legend->item(i)->setTextColor(colors[i % CHANNELS]);
            }
        }

        ui->plot->graph(i)->addData(dataPointNumber, value[i]);
    }

    dataPointNumber++;
}
